package gatehttp

import (
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"gitee.com/segeln/grit/conf"
	"gitee.com/segeln/grit/log"
	"gitee.com/segeln/grit/registry"
	"gitee.com/segeln/grit/toolkit/addr"
	"github.com/gorilla/mux"
)

type FrontActionFunc func(h http.Handler) http.Handler

type GateHttp struct {
	// http服务器
	server *http.Server
	//静态文件目录
	//staticDir []string

	opts *conf.Config

	routes []Route

	FrontAction func(h http.Handler) http.Handler //FrontActionFunc

	Registry registry.Registry

	signRegistry chan int
}
type Route struct {
	//Route   string
	//Method  string
	Method      []string
	Pattern     string
	HandlerFunc http.HandlerFunc //func(http.ResponseWriter, *http.Request)
	Desc        string
}

func (this *GateHttp) AddRoute(route Route) {
	this.routes = append(this.routes, route) //gatehttp.Route{[]string{"GET"}, "/index/{id}", hander1})
}
func (this *GateHttp) SetOpts(o *conf.Config) {
	this.opts = o
}
func (this *GateHttp) GetOpts() *conf.Config {
	return this.opts
}

func (this *GateHttp) GetRoutes() []Route {
	return this.routes
}

func (this *GateHttp) handlerPreprocess(writer http.ResponseWriter, request *http.Request) {
	vars := mux.Vars(request) //获取值
	fmt.Println("method:", request.Method)
	fmt.Println("myhandler")
	fmt.Println("user:", vars["id"])
}

func (this *GateHttp) Init() {

	this.AddRoute(Route{[]string{"GET"}, "/check", this.handerCheck, "check"})
	//this.AddRoute(Route{[]string{"GET"}, "/close", this.handerClose})
	router := this.newRouter() //   mux.NewRouter()

	this.server = &http.Server{
		Addr:         fmt.Sprintf(":%d", this.opts.Port), //   ":1210",
		WriteTimeout: time.Second * 20,                   //设置20秒的写超时
		ReadTimeout:  time.Second * 20,
		Handler:      router,
	}
	//	r.HandleFunc("/", YourHandler)
	/*
		for _, r := range this.Routes {
			//	mux.HandleFunc("/bye", sayBye)
			mux.HandleFunc(r.Pattern, r.Handler)
		}
	*/
}

func (this *GateHttp) handerCheck(writer http.ResponseWriter, request *http.Request) {
	//fmt.Fprintln(w, "consulCheck")
	writer.Write([]byte("consulCheck"))
}
func (this *GateHttp) handerClose(writer http.ResponseWriter, request *http.Request) {
	//fmt.Fprintln(w, "consulCheck")
	//writer.Write([]byte("consulCheck"))

	this.Registry.Deregister()
}

func (this *GateHttp) newRouter() *mux.Router {
	//r := mux.NewRouter().StrictSlash(false)
	r := mux.NewRouter().StrictSlash(true)
	router := r.PathPrefix("/").Subrouter()
	for _, route := range this.routes { //} routes {
		var handler http.Handler
		handler = route.HandlerFunc
		handler = this.RestFulServeHTTP(handler) //, route.Name)
		for _, method := range route.Method {
			//		router.Methods(method).Path(route.Pattern).Name(route.Name).Handler(handler)
			//router.Methods(method).Path(route.Pattern).Handler(handler)
			fmt.Println("Pattern:", route.Pattern)
			router.Methods(method).Path(route.Pattern).Handler(handler) //route.HandlerFunc)
		}
	}
	for _, v := range this.opts.StaticDir {
		catalog := fmt.Sprintf("/%s/", v)
		router.PathPrefix(catalog).Handler(http.StripPrefix(catalog, http.FileServer(http.Dir(fmt.Sprintf(".%s", catalog)))))
	}
	if this.FrontAction != nil {
		router.Use(this.FrontAction)
	}
	//	router.PathPrefix("/public/").Handler(http.StripPrefix("/public/", http.FileServer(http.Dir("./public/"))))
	//	router.PathPrefix("/views/").Handler(http.StripPrefix("/views/", http.FileServer(http.Dir("./views/"))))
	//	router.PathPrefix("/upload/").Handler(http.StripPrefix("/upload/", http.FileServer(http.Dir("./upload/"))))
	return router
}

func (this *GateHttp) Run() error {
	ip, err := addr.ExtractIP()
	if err != nil {
		log.Exitln("获取IP失败")
		return err
	}
	log.Init(this.opts.Name, ip, this.opts.Port)
	//注册中心注册服务
	serinfo := &registry.ServiceInfo{}
	serinfo.Address = ip //addr.ExtractIP()
	serinfo.Port = this.opts.Port
	serinfo.Name = this.opts.Name       // "sergggg"
	serinfo.ID = this.opts.Sid          //.ServiceID //   "id12"
	serinfo.Version = this.opts.Version //  "v1.1"
	//	this.opts.Registry.Init(serinfo)
	//	this.opts.Registry.Register()
	this.Registry.Init(serinfo)
	fmt.Println("Listen prot：", this.opts.Port)
	//grpc consul健康检查
	this.signRegistry = make(chan int)
	go this.serRegister(this.signRegistry)
	go this.signalHandle()
	log.Infoln("Http Gate server Name :", this.opts.Name)
	log.Infoln("Http Gate server Name :", this.Registry.GetSid()) // fmt.Sprintf("%s_%s", this.opts.Name, this.opts.Sid))
	log.Infoln("Http Gate server Listen :", this.opts.Port)       //.fmt.Sprintf(":%v", this.Port))

	//	http.Handle("/template/", http.StripPrefix("/template/", http.FileServer(http.Dir("./template"))))
	//http.Handle("/", http.FileServer(http.Dir("/tmp")))

	err = this.server.ListenAndServe()
	if err != nil {
		log.Errorln("Listen server failed:error:", err)
	}
	log.Errorln("Server exited")
	return nil
}

//服务注册
func (this *GateHttp) serRegister(exit chan int) {
	t := time.NewTicker(time.Duration(this.opts.RegistryCfg.Interval) * time.Second)
	for {
		select {
		case <-t.C:
			//err := s.opts.Server.ServiceRegister()
			err := this.Registry.Register()
			if err != nil {
				log.Warningln("service run Server.Register error: ", err)
			}
		case sign := <-exit:
			t.Stop()
			if sign == 2 {
				this.Close()
			}
			return
		}
	}
}
func (this *GateHttp) signalHandle() {
	for {
		ch := make(chan os.Signal)
		signal.Notify(ch, syscall.SIGINT, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGHUP)
		sig := <-ch
		//log.Errorln("Signal received:  ", sig)
		//interrupt
		switch sig {
		// 2 信号量
		case syscall.SIGINT:
			log.Errorln("get SIGINT")
			//this.ex <- true
			this.signRegistry <- 2
			//this.Registry.Deregister()
			//os.Exit(1)
		default:
			log.Errorln("Receive Signal :", sig)
		}
	}
}

func (this *GateHttp) Close() {
	log.Infoln("Close.................")
	//删除注册信息
	this.Registry.Deregister()
	//服务清空。。。。。。。。
	log.Flush()
	//。。。。。。。
	os.Exit(1)
}

//func (this *GateHttp) RestFulServeHTTP(inner http.Handler, name string) http.Handler {
func (this *GateHttp) RestFulServeHTTP(inner http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()
		inner.ServeHTTP(w, r)
		///check
		if r.RequestURI != "/check" {
			log.Infoln(r.Method, r.RequestURI, r.Form, time.Since(start))
		}
	})
}

func (this *GateHttp) BeforeAction(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		//tm.timesCalled++
		log.Infoln("url:", r.URL) // r.URL

		h.ServeHTTP(w, r)
	})
}
